#include <stdlib.h>
#include <stdio.h>
#include <glut.h>
#include <GLAux.h>
#include <iostream>
#include <fstream> 
#include <string> 
#include <vector> 

using namespace std;

void loadFile( char* filename );

HDC			hDC=NULL;                           // Private GDI Device Context
HGLRC       hRC=NULL;                       // Permanent Rendering Context
HWND        hWnd=NULL;                      // Holds Our Window Handle
HINSTANCE   hInstance;

bool	keys[256];			// Array Used For The Keyboard Routine
bool	active=TRUE;		// Window Active Flag Set To TRUE By Default
bool	fullscreen=TRUE;
GLint	objModel;
GLuint      texture[1];
char* textur ="Data/NeHe.bmp";

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 

GLfloat rquad;

//gerichtete Lichtquelle
GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };	
GLfloat diffuse[] = { 0.0, 0.0, 1.0, 1.0 };  
GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position[] = {1.0, 0.0, 0.0, 0.0 };	

//Punktlichtquelle
GLfloat ambient1[] = { 0.0, 0.0, 0.0, 1.0 };	
GLfloat diffuse1[] = { 1.0, 0.0, 0.0, 0.0 }; 
GLfloat specular1[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position1[] = { 0.0, 0.0, 0.0, 1.0 };
	
//Spotlight
GLfloat ambient2[] = { 0.0, 0.0, 0.0, 1.0 };	
GLfloat diffuse2[] = { 1.0, 1.0, 0.0, 1.0 };
GLfloat specular2[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position2[] = { 0.0, 10.0, 0.0, 1.0 };
GLfloat spot_dir[] = {0.0, -10.0, 0}; 

//Material No.1
GLfloat mat_emission[] = {0.0, 0.0, 0.0, 0.0};
GLfloat mat_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat shininess[] = { 40.0 };



typedef struct vertice{
	float v[3];
	float n[3];
};

//struct Triangle {
//       
//	int v1;
//	int v2;
//	int v3;
//       
//};
//
//struct Vertex {
//      
//	float x;
//	float y;
//	float z;
//            
//};


void initDisplayList()
{
	objModel = glGenLists(2);
	glNewList(objModel, GL_COMPILE);
	glBegin(GL_TRIANGLES);
		loadFile("cube.obj");
	glEnd();
	glEndList();
}

void init(void) 
{

glLoadIdentity ();             
gluLookAt (0.0, 3.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);


glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);

//Punktlichtquelle
glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
glLightfv(GL_LIGHT1, GL_SPECULAR, specular1);
glLightfv(GL_LIGHT1, GL_POSITION, position1);

//Spotlight
glLightfv(GL_LIGHT2, GL_AMBIENT, ambient2);
glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse2);
glLightfv(GL_LIGHT2, GL_SPECULAR, specular2);
glLightfv(GL_LIGHT2, GL_POSITION, position2);
glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, spot_dir);
glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 20.0); 
glLightf(GL_LIGHT2, GL_SPOT_EXPONENT, 0.6); 

glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, shininess);

glClearColor (0.0, 0.0, 0.0, 0.0);	
glShadeModel (GL_SMOOTH);


glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0 );
glEnable(GL_LIGHT1 );
glEnable(GL_LIGHT2 );
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);

initDisplayList();
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   
}
//
//AUX_RGBImageRec *LoadBMP(char *Filename)
//{
//    FILE *File=NULL;
//	if (!Filename)                          // Make Sure A Filename Was Given
//	{
//		return NULL;                        // If Not Return NULL
//	}
//	File=fopen(Filename,"r");               // Check To See If The File Exists
//
//	if (File)                               // Does The File Exist?
//	{
//		fclose(File);                       // Close The Handle
//		return auxDIBImageLoad(Filename);   // Load The Bitmap And Return A Pointer
//
//	}
//	return NULL;
//}
//
//
//////TExture Mapping
////
//int LoadGLTextures()                                // Load Bitmaps And Convert To Textures
//{
//	int Status=FALSE;
//	AUX_RGBImageRec *TextureImage[1];                   // Create Storage Space For The Texture
//	memset(TextureImage,0,sizeof(void *)*1);
//
//
//	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
//	if (TextureImage[0]=LoadBMP(textur))
//	{
//			Status=TRUE;                            // Set The Status To TRUE
//			glGenTextures(1, &texture[0]);                  // Create The Texture
// 
//			// Typical Texture Generation Using Data From The Bitmap
//			glBindTexture(GL_TEXTURE_2D, texture[0]);
//			// Generate The Texture
//			glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
//			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
//			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
//	}
//
//	if (TextureImage[0])                            // If Texture Exists
//	{
//			if (TextureImage[0]->data)                   // If Texture Image Exists
//			{
//				free(TextureImage[0]->data);             // Free The Texture Image Memory
//			}
// 
//			free(TextureImage[0]);                      // Free The Image Structure
//	}
//    return Status;                              // Return The Status
//}



void loadFile( char* filename )
{
    ifstream file( filename );
    if (!file) exit( 1 );

    int a,b,c;
    string string1;
    string line;
    vector<vertice> vertices;

    glBegin( GL_TRIANGLES );
    while ( getline( file, line) )
    {
        cout << line << endl;
        vertice v;

        if (sscanf(line.c_str(),"v %f %f %f",&(v.v[0]),&(v.v[1]),&(v.v[2])))
        {
            if((v.v[0]>=100)||(v.v[1] >= 100)||(v.v[2]>=100)||(v.v[0]<=-100)||(v.v[1]<= -100)||(v.v[2]<=-100)){
                return;
            }
            vertices.push_back( v );
        }
		
        if (sscanf( line.c_str(), "f %i %i %i", &a, &b, &c ) )
        {
            a--; b--; c--;
           
            //x normalisieren
            v.n[0]=(((vertices[a].v[1]-vertices[b].v[1])*(vertices[b].v[2]-vertices[c].v[2]))-((vertices[a].v[2]-vertices[b].v[2])*(vertices[b].v[1]-vertices[c].v[1])));
            //y normalisieren
            v.n[1]=(((vertices[a].v[2]-vertices[b].v[2])*(vertices[b].v[0]-vertices[c].v[0]))-((vertices[a].v[0]-vertices[b].v[0])*(vertices[b].v[2]-vertices[c].v[2])));
            //z normalisieren
            v.n[2]=(((vertices[a].v[0]-vertices[b].v[0])*(vertices[b].v[1]-vertices[c].v[1]))-((vertices[a].v[1]-vertices[b].v[1])*(vertices[b].v[0]-vertices[c].v[0])));

            float temp = (v.n[0]*v.n[0])+(v.n[1]*v.n[1])+(v.n[2]*v.n[2]);
            float temptemp;
            temptemp=sqrt(temp);
            if(temptemp == 0){
                temp = 1;
            }else{
                temp = temptemp;
            }
           
            temptemp = v.n[0];
            v.n[0]= temptemp/temp;
            temptemp = v.n[1];
            v.n[1]= temptemp/temp;
            temptemp = v.n[2];
            v.n[2]= temptemp/temp;

           
            glTranslatef(0, 0, 12);
            //FLAT SHADING Normalen zuweisen
            glNormal3f(v.n[0], v.n[1], v.n[2]);
            //GOURAUD SHADING Normalen zuweisen
            temp = (v.n[0]+v.n[1]+v.n[2])/3;
            glNormal3f(temp, temp, temp);
            //ENDE
            glEnable(GL_TEXTURE_2D);   

            glTexCoord2f(0.0f, 0.0f);
            glVertex3f( vertices[a].v[0], vertices[a].v[1], vertices[a].v[2] );
            glTexCoord2f(1.0f, 1.0f);
            glVertex3f( vertices[b].v[0], vertices[b].v[1], vertices[b].v[2] );
            glTexCoord2f(1.0f, 0.0f);
            glVertex3f( vertices[c].v[0], vertices[c].v[1], vertices[c].v[2] );

        }
       
    }
    glEnd();
    return;
}

void GrebAlexanderDisplay(void)
{
//
//if (!LoadGLTextures())                          // Jump To Texture Loading Routine ( NEW )
//{
//	return;                           // If Texture Didn't Load Return FALSE ( NEW )
//}
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// glColor3f (1.0, 0.0, 1.0);
glLoadIdentity ();   
   

gluLookAt (0.0, 3.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
      
////Schachbrett
//LoadGLTextures(); 
//textur ="Data/NeHe.bmp";
//glEnable(GL_TEXTURE_2D);	
//glBindTexture(GL_TEXTURE_2D, texture[0]);
glTranslatef(0.0f,0.0f,0.0f);
glCallList(objModel);
//glDisable(GL_TEXTURE_2D);


glPushMatrix(); 
	glTranslatef(-2.0f,1.0f,-3.0f);
	glRotatef(rquad,0.0f,1.0f,0.0f);
	//Stamm
	glPushMatrix();
	//glColor3f(1.0f,0.5f,0.0f);
		glTranslatef(0.0f,-1.0f,0.0f);
		glScalef(1.0,2.0,1.0);
		glutSolidCube(1.0);
	glPopMatrix();
   
	//1. Ast
	glPushMatrix();
	//glColor3f(1.0f,0.5f,0.0f);
		glRotatef(60,0.0f,0.0f,1.0f);
		glTranslatef(0.0f,1.0f,0.0f);
		glScalef(1.0,2.0,1.0);
		glutSolidCube(1.0);
	glPopMatrix();

	//2. Ast
	glPushMatrix();
	//glColor3f(1.0f,0.5f,0.0f);
		glRotatef(120,0.0f,1.0f,0.0f);
		glRotatef(60,0.0f,0.0f,1.0f);
		glTranslatef(0.0f,1.0f,0.0f);
		glScalef(1.0,2.0,1.0);
		glutSolidCube(1.0);
	glPopMatrix();

	//3. Ast
	glPushMatrix();
	//glColor3f(0.0f,0.0f,0.0f);
		glRotatef(240,0.0f,1.0f,0.0f);
		glRotatef(60,0.0f,0.0f,1.0f);
		glTranslatef(0.0f,1.0f,0.0f);
		glScalef(1.0,2.0,1.0);
		glutSolidCube(1.0);
	glPopMatrix();
glPopMatrix();

glPushMatrix();
	glTranslatef(-4.0f,0.0f,0.0f);        
	glutSolidSphere (1.0, 100, 100);
glPopMatrix();

glPushMatrix();
	glTranslatef(4.0f,0.0f,0.0f);        
	glutSolidSphere (1.0, 100, 100);
glPopMatrix();

//glPushMatrix();
//	glTranslatef(0.0f,0.0f,0.0f);
//	loadFile("cube.obj");
//glPopMatrix();

glFlush ();

}

void idle()
{
glutPostRedisplay();
rquad += 0.1;
}


void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 60.0);
glMatrixMode (GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
switch (key) {
	case 27:
		exit(0);
		break;
}
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (500, 500); 
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(GrebAlexanderDisplay); 
glutIdleFunc(idle);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
//initDisplayList();
glutMainLoop();
return 0;
}



